package com.yykj.hospital.server.service.banci.impl;

import com.yykj.common.constant.CommonConstant;
import com.yykj.common.enums.BanCiType;
import com.yykj.common.enums.HospitalOnlineTypeEnum;
import com.yykj.hospital.client.dto.DoctorDTO;
import com.yykj.hospital.client.form.banci.BanCIListFrom;
import com.yykj.hospital.server.model.entity.banci.HospitalBanCi;
import com.yykj.hospital.server.model.entity.banci.HospitalDoctorBanCi;
import com.yykj.hospital.server.model.entity.banci.HospitalDoctorVisitLevel;
import com.yykj.hospital.server.model.repository.banci.HospitalBanCiRepository;
import com.yykj.hospital.server.model.repository.banci.HospitalDoctorVisitLevelRepository;
import com.yykj.hospital.server.service.banci.BanCiExportService;
import com.yykj.hospital.server.service.banci.BanCiService;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class BanCiExportServiceImpl implements BanCiExportService {
    @Override
    public Workbook exportDoctorOnlineBanCi(BanCIListFrom form) {

        List<HospitalDoctorBanCi> doctorBanCiList = banCiService.getDoctorBanCiList(form);

        Map<String, HospitalDoctorBanCi> banCiMap = new HashMap<>();
        List<String> doctorIds = new ArrayList<>();
        Map<String, DoctorDTO> doctorDTOMap = new HashMap<>();
        String key;
        String onlineKey = null;
        Integer value;
        Map<String, Integer> doctorTotal = new HashMap<>();
        Map<String, Integer> doctorUsed = new HashMap<>();
        String dayStr = null;

        for (HospitalDoctorBanCi doctorBanCi : doctorBanCiList) {
            if (!doctorIds.contains(doctorBanCi.getDoctorId())) {
                doctorIds.add(doctorBanCi.getDoctorId());
            }
            dayStr = doctorBanCi.getDay().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
            key = doctorBanCi.getDoctorId() + "_" + doctorBanCi.getBanCiId() + "_" + dayStr;

            banCiMap.put(key, doctorBanCi);
            DoctorDTO doctorDTO = doctorDTOMap.get(doctorBanCi.getDoctorId());
            if (doctorDTO == null) {
                doctorDTO = new DoctorDTO();
                BeanUtils.copyProperties(doctorBanCi, doctorDTO);
                doctorDTOMap.put(doctorBanCi.getDoctorId(), doctorDTO);
            }
            onlineKey = doctorBanCi.getDoctorId() + dayStr + HospitalOnlineTypeEnum.pic;
            value = doctorTotal.getOrDefault(onlineKey, 0);
            doctorTotal.put(onlineKey, doctorBanCi.getPic() + value);
            value = doctorUsed.getOrDefault(onlineKey, 0);
            doctorUsed.put(onlineKey, doctorBanCi.getPicUsed() + value);

            onlineKey = doctorBanCi.getDoctorId() + dayStr + HospitalOnlineTypeEnum.video;
            value = doctorTotal.getOrDefault(onlineKey, 0);
            doctorTotal.put(onlineKey, doctorBanCi.getVideo() + value);
            value = doctorUsed.getOrDefault(onlineKey, 0);
            doctorUsed.put(onlineKey, doctorBanCi.getVideoUsed() + value);

            onlineKey = doctorBanCi.getDoctorId() + dayStr + HospitalOnlineTypeEnum.voice;
            value = doctorTotal.getOrDefault(onlineKey, 0);
            doctorTotal.put(onlineKey, doctorBanCi.getVoice() + value);
            value = doctorUsed.getOrDefault(onlineKey, 0);
            doctorUsed.put(onlineKey, doctorBanCi.getVoiceUsed() + value);


        }

        HSSFWorkbook workbook = new HSSFWorkbook();

        HSSFSheet sheet = workbook.createSheet("医生班次");

        HSSFCellStyle style = workbook.createCellStyle();
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setWrapText(true);

        int rowIndex = 0;
        int colIndex = 0;
        HSSFRow row0 = sheet.createRow(rowIndex++);
        HSSFRow row1 = sheet.createRow(rowIndex++);
        HSSFRow row2 = sheet.createRow(rowIndex++);
        row0.setHeight((short) 500);
        row1.setHeight((short) 500);
        row2.setHeight((short) 500);

        HSSFCell cell_00 = row0.createCell(colIndex++);
        cell_00.setCellValue("出诊科室");
        cell_00.setCellStyle(style);

        HSSFCell cell_01 = row0.createCell(colIndex++);
        cell_01.setCellValue("出诊医生");
        cell_01.setCellStyle(style);

        HSSFCell cell_02 = row0.createCell(colIndex);
        cell_02.setCellValue("日期");
        cell_02.setCellStyle(style);

        HSSFCell cell_12 = row1.createCell(colIndex);
        cell_12.setCellValue("星期");
        cell_12.setCellStyle(style);

        HSSFCell cell_22 = row2.createCell(colIndex);
        cell_22.setCellValue("类型");
        cell_22.setCellStyle(style);
        sheet.setColumnWidth(2, 5000);


        sheet.addMergedRegion(new CellRangeAddress(0, 2, 0, 0));
        sheet.addMergedRegion(new CellRangeAddress(0, 2, 1, 1));

        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate startDate = LocalDate.parse(form.getStartDate(), dateTimeFormatter);
        LocalDate endDate = LocalDate.parse(form.getEndDate(), dateTimeFormatter);

        long days = endDate.toEpochDay() - startDate.toEpochDay();

        log.info("period = {}", days);

        colIndex++;
        int startCol = colIndex;
        HSSFCell cell;
        for (int i = 0; i <= days; i++) {
            LocalDate localDate = startDate.plusDays(i);

            HSSFCell cell1 = row0.createCell(startCol + i * 3);
            cell1.setCellValue(localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
            cell1.setCellStyle(style);

            HSSFCell cell2 = row1.createCell(startCol + i * 3);
            cell2.setCellValue(CommonConstant.dayOfWeekMap.get(localDate.getDayOfWeek().getValue()));
            cell2.setCellStyle(style);


            cell = row2.createCell(startCol + i * 3);
            cell.setCellValue("视频");
            cell.setCellStyle(style);

            cell = row2.createCell(startCol + i * 3 + 1);
            cell.setCellValue("语音");
            cell.setCellStyle(style);

            cell = row2.createCell(startCol + i * 3 + 2);
            cell.setCellValue("图文");
            cell.setCellStyle(style);

            sheet.addMergedRegion(new CellRangeAddress(0, 0, startCol + i * 3, startCol + i * 3 + 2));
            sheet.addMergedRegion(new CellRangeAddress(1, 1, startCol + i * 3, startCol + i * 3 + 2));
        }

        List<HospitalBanCi> banCiList = banCiRepository.findAllByHospitalIdAndStatusAndTypeOrderByStartTime(form.getHospitalId(), true, BanCiType.online);

        HospitalBanCi dayAll = new HospitalBanCi();
        dayAll.setId(0);
        dayAll.setName("全天");
        for (HospitalBanCi hospitalBanCi : banCiList) {

            if (dayAll.getStartTime() == null || hospitalBanCi.getStartTime().isBefore(dayAll.getStartTime())) {
                dayAll.setStartTime(hospitalBanCi.getStartTime());
            }
            if (dayAll.getEndTime() == null || hospitalBanCi.getEndTime().isAfter(dayAll.getEndTime())) {
                dayAll.setEndTime(hospitalBanCi.getEndTime());
            }
        }
        banCiList.add(dayAll);

        int firstMergeRow = rowIndex;
        int lastMergeRow = 0;
        int maxCol = 0;
        for (String doctorId : doctorIds) {

            for (HospitalBanCi hospitalBanCi : banCiList) {
                HSSFRow row = sheet.createRow(rowIndex++);
                int col = 0;

                DoctorDTO doctorDTO = doctorDTOMap.get(doctorId);
                row.createCell(col++).setCellValue(doctorDTO.getDepName());
                row.createCell(col++).setCellValue(doctorDTO.getDoctorName());
                row.createCell(col++).setCellValue(hospitalBanCi.getName() + "\n(" + hospitalBanCi.getStartTime() + "-" + hospitalBanCi.getEndTime() + ")");

                for (int i = 0; i <= days; i++) {

                    for (HospitalOnlineTypeEnum type : HospitalOnlineTypeEnum.values()) {
                        LocalDate localDate = startDate.plusDays(i);
                        dayStr = localDate.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
                        key = doctorId + "_" + hospitalBanCi.getId() + "_" + dayStr;
                        HospitalDoctorBanCi hospitalDoctorBanCi = banCiMap.get(key);

                        if (hospitalDoctorBanCi != null) {
                            switch (type) {
                                case pic:
                                    row.createCell(col++).setCellValue((hospitalDoctorBanCi.getPic() - hospitalDoctorBanCi.getPicUsed()) + "/" + hospitalDoctorBanCi.getPic());
                                    break;
                                case voice:
                                    row.createCell(col++).setCellValue((hospitalDoctorBanCi.getVoice() - hospitalDoctorBanCi.getVoiceUsed()) + "/" + hospitalDoctorBanCi.getVoice());
                                    break;
                                case video:
                                    row.createCell(col++).setCellValue((hospitalDoctorBanCi.getVideo() - hospitalDoctorBanCi.getVideoUsed()) + "/" + hospitalDoctorBanCi.getVideo());
                                    break;
                                default:
                                    break;
                            }
                        } else {
                            //全天
                            if (hospitalBanCi.getId() == 0) {
                                switch (type) {
                                    case pic:
                                        onlineKey = doctorId + dayStr + HospitalOnlineTypeEnum.pic;
                                        break;
                                    case voice:
                                        onlineKey = doctorId + dayStr + HospitalOnlineTypeEnum.voice;
                                        break;
                                    case video:
                                        onlineKey = doctorId + dayStr + HospitalOnlineTypeEnum.video;
                                        break;
                                    default:
                                        break;
                                }
                                if (doctorTotal.get(onlineKey) == null) {
                                    row.createCell(col++).setCellValue("-");
                                } else {
                                    row.createCell(col++).setCellValue((doctorTotal.get(onlineKey) - doctorUsed.get(onlineKey)) + "/" + doctorTotal.get(onlineKey));
                                }

                            } else {
                                row.createCell(col++).setCellValue("-");
                            }
                        }

                    }
                    maxCol = col;
                    for (int j = 0; j < maxCol; j++) {
                        cell = row.getCell(j);
                        cell.setCellStyle(style);
                    }
                }


            }
            lastMergeRow = rowIndex - 1;
            sheet.addMergedRegion(new CellRangeAddress(firstMergeRow, lastMergeRow, 0, 0));
            sheet.addMergedRegion(new CellRangeAddress(firstMergeRow, lastMergeRow, 1, 1));
            firstMergeRow = rowIndex;

        }


        return workbook;
    }

    @Override
    public Workbook exportDoctorAppointmentBanCi(BanCIListFrom form) {

        List<HospitalDoctorBanCi> doctorBanCiList = banCiService.getDoctorBanCiList(form);

        Map<String, HospitalDoctorBanCi> banCiMap = new HashMap<>();
        List<String> doctorIds = new ArrayList<>();
        Map<String, DoctorDTO> doctorDTOMap = new HashMap<>();
        String key;
        String appointmentKey = null;
        Integer value;
        Map<String, Integer> doctorTotal = new HashMap<>();
        Map<String, Integer> doctorUsed = new HashMap<>();
        String dayStr = null;

        for (HospitalDoctorBanCi doctorBanCi : doctorBanCiList) {
            if (!doctorIds.contains(doctorBanCi.getDoctorId())) {
                doctorIds.add(doctorBanCi.getDoctorId());
            }
            dayStr = LocalDateTime.of(doctorBanCi.getDay(), doctorBanCi.getStartTime()).format(DateTimeFormatter.ofPattern("yyyyMMdd"));
            key = doctorBanCi.getDoctorId() + "_" + doctorBanCi.getBanCiId() + "_" + doctorBanCi.getLevelId() + "_" + dayStr;
            HospitalDoctorBanCi hospitalDoctorBanCi = banCiMap.get(key);
            if (hospitalDoctorBanCi == null) {
                hospitalDoctorBanCi = new HospitalDoctorBanCi();
                BeanUtils.copyProperties(doctorBanCi, hospitalDoctorBanCi);
            } else {
                hospitalDoctorBanCi.setAppointment(hospitalDoctorBanCi.getAppointment() + doctorBanCi.getAppointment());
                hospitalDoctorBanCi.setAppointmentUsed(hospitalDoctorBanCi.getAppointmentUsed() + doctorBanCi.getAppointmentUsed());
            }
            banCiMap.put(key, hospitalDoctorBanCi);
            DoctorDTO doctorDTO = doctorDTOMap.get(doctorBanCi.getDoctorId());
            if (doctorDTO == null) {
                doctorDTO = new DoctorDTO();
                BeanUtils.copyProperties(doctorBanCi, doctorDTO);
                doctorDTOMap.put(doctorBanCi.getDoctorId(), doctorDTO);
            }
            appointmentKey = doctorBanCi.getDoctorId() + "_" + doctorBanCi.getLevelId() + "_" + dayStr;

            value = doctorTotal.getOrDefault(appointmentKey, 0);
            doctorTotal.put(appointmentKey, doctorBanCi.getAppointment() + value);
            value = doctorUsed.getOrDefault(appointmentKey, 0);
            doctorUsed.put(appointmentKey, doctorBanCi.getAppointmentUsed() + value);

        }

        HSSFWorkbook workbook = new HSSFWorkbook();

        HSSFSheet sheet = workbook.createSheet("医生班次");

        HSSFCellStyle style = workbook.createCellStyle();
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setWrapText(true);

        int rowIndex = 0;
        int colIndex = 0;
        HSSFRow row0 = sheet.createRow(rowIndex++);
        HSSFRow row1 = sheet.createRow(rowIndex++);
        row0.setHeight((short) 500);
        row1.setHeight((short) 500);

        HSSFCell cell_00 = row0.createCell(colIndex++);
        cell_00.setCellValue("出诊科室");
        cell_00.setCellStyle(style);

        HSSFCell cell_01 = row0.createCell(colIndex++);
        cell_01.setCellValue("出诊医生");
        cell_01.setCellStyle(style);

        HSSFCell cell_02 = row0.createCell(colIndex++);
        cell_02.setCellValue("出诊级别");
        cell_02.setCellStyle(style);

        HSSFCell cell_03 = row0.createCell(colIndex);
        cell_03.setCellValue("日期");
        cell_03.setCellStyle(style);

        HSSFCell cell_13 = row1.createCell(colIndex);
        cell_13.setCellValue("星期");
        cell_13.setCellStyle(style);
        sheet.setColumnWidth(colIndex, 4000);


        sheet.addMergedRegion(new CellRangeAddress(0, 1, 0, 0));
        sheet.addMergedRegion(new CellRangeAddress(0, 1, 1, 1));
        sheet.addMergedRegion(new CellRangeAddress(0, 1, 2, 2));

        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate startDate = LocalDate.parse(form.getStartDate(), dateTimeFormatter);
        LocalDate endDate = LocalDate.parse(form.getEndDate(), dateTimeFormatter);

        long days = endDate.toEpochDay() - startDate.toEpochDay();

        log.info("period = {}", days);

        colIndex++;
        int startCol = colIndex;
        HSSFCell cell;
        for (int i = 0; i <= days; i++) {
            LocalDate localDate = startDate.plusDays(i);

            HSSFCell cell1 = row0.createCell(startCol + i);
            cell1.setCellValue(localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
            cell1.setCellStyle(style);
            sheet.setColumnWidth(startCol + i, 3000);

            HSSFCell cell2 = row1.createCell(startCol + i);
            cell2.setCellValue(CommonConstant.dayOfWeekMap.get(localDate.getDayOfWeek().getValue()));
            cell2.setCellStyle(style);

        }

        List<HospitalBanCi> banCiList = banCiRepository.findAllByHospitalIdAndStatusAndTypeOrderByStartTime(form.getHospitalId(), true, BanCiType.appointment);
        List<HospitalDoctorVisitLevel> levelList = visitLevelRepository.findAllByHospitalId(form.getHospitalId());

        HospitalBanCi dayAll = new HospitalBanCi();
        dayAll.setId(0);
        dayAll.setName("全天");
        for (HospitalBanCi hospitalBanCi : banCiList) {

            if (dayAll.getStartTime() == null || hospitalBanCi.getStartTime().isBefore(dayAll.getStartTime())) {
                dayAll.setStartTime(hospitalBanCi.getStartTime());
            }
            if (dayAll.getEndTime() == null || hospitalBanCi.getEndTime().isAfter(dayAll.getEndTime())) {
                dayAll.setEndTime(hospitalBanCi.getEndTime());
            }
        }
        banCiList.add(dayAll);

        int firstMergeRow = rowIndex;
        int lastMergeRow = 0;
        int maxCol = 0;
        for (String doctorId : doctorIds) {
            for (HospitalDoctorVisitLevel level : levelList) {
                for (HospitalBanCi hospitalBanCi : banCiList) {
                    HSSFRow row = sheet.createRow(rowIndex++);
                    int col = 0;
                    DoctorDTO doctorDTO = doctorDTOMap.get(doctorId);
                    row.createCell(col++).setCellValue(doctorDTO.getDepName());
                    row.createCell(col++).setCellValue(doctorDTO.getDoctorName());
                    row.createCell(col++).setCellValue(level.getName());
                    row.createCell(col++).setCellValue(hospitalBanCi.getName() + "\n(" + hospitalBanCi.getStartTime() + "-" + hospitalBanCi.getEndTime() + ")");

                    for (int i = 0; i <= days; i++) {
                        LocalDate localDate = startDate.plusDays(i);
                        dayStr = localDate.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
                        key = doctorId + "_" + hospitalBanCi.getId() + "_" + level.getId() + "_" + dayStr;
                        HospitalDoctorBanCi hospitalDoctorBanCi = banCiMap.get(key);
                        if (hospitalDoctorBanCi != null) {
                            row.createCell(col++).setCellValue((hospitalDoctorBanCi.getAppointment() - hospitalDoctorBanCi.getAppointmentUsed()) + "/" + hospitalDoctorBanCi.getAppointment());
                        } else {
                            //全天
                            if (hospitalBanCi.getId() == 0) {
                                appointmentKey = doctorId + "_" + level.getId() + "_" + dayStr;
                                if (doctorTotal.get(appointmentKey) == null) {
                                    row.createCell(col++).setCellValue("-");
                                } else {
                                    row.createCell(col++).setCellValue((doctorTotal.get(appointmentKey) - doctorUsed.get(appointmentKey)) + "/" + doctorTotal.get(appointmentKey));
                                }
                            } else {
                                row.createCell(col++).setCellValue("-");
                            }
                        }

                        maxCol = col;
                        for (int j = 0; j < maxCol; j++) {
                            cell = row.getCell(j);
                            cell.setCellStyle(style);
                        }
                    }
                }

            }
            lastMergeRow = rowIndex - 1;
            sheet.addMergedRegion(new CellRangeAddress(firstMergeRow, lastMergeRow, 0, 0));
            sheet.addMergedRegion(new CellRangeAddress(firstMergeRow, lastMergeRow, 1, 1));
            for (int j = 0; j < levelList.size(); j++) {
                sheet.addMergedRegion(new CellRangeAddress(firstMergeRow + j * banCiList.size(),
                        firstMergeRow + (j + 1) * banCiList.size() - 1, 2, 2));
            }
            firstMergeRow = rowIndex;

        }


        return workbook;
    }

    private HospitalBanCiRepository banCiRepository;

    private HospitalDoctorVisitLevelRepository visitLevelRepository;

    private BanCiService banCiService;

    @Autowired
    public void setBanCiRepository(HospitalBanCiRepository banCiRepository) {
        this.banCiRepository = banCiRepository;
    }

    @Autowired
    public void setVisitLevelRepository(HospitalDoctorVisitLevelRepository visitLevelRepository) {
        this.visitLevelRepository = visitLevelRepository;
    }

    @Autowired
    public void setBanCiService(BanCiService banCiService) {
        this.banCiService = banCiService;
    }
}
